package com.bc004346.travelus.fragment;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.TextSwitcher;
import android.widget.TextView;
import android.widget.ViewSwitcher;

import com.bc004346.travelus.R;
import com.bc004346.travelus.SettingsActivity;
import com.bc004346.travelus.StandbyActivity;
import com.bc004346.travelus.model.TravelUsException;
import com.bc004346.travelus.model.TravelUsUnavailableException;
import com.bc004346.travelus.model.domain.Flight;
import com.bc004346.travelus.model.domain.Passenger;
import com.bc004346.travelus.utility.Utility;

import java.util.ArrayList;
import java.util.Date;
import java.util.Set;

import static com.bc004346.travelus.utility.Utility.DAY_DATE;
import static com.bc004346.travelus.utility.Utility.MILITARY_TIME;
import static com.bc004346.travelus.utility.Utility.MINUTE;
import static com.bc004346.travelus.utility.Utility.SECOND;
import static com.bc004346.travelus.utility.Utility.log;

/**
 * Created by Renats on 9/8/2014.
 * Flight details fragment
 */
public class FlightDetailsFragment extends Fragment {

    //<editor-fold desc="Members">
    public static final String EXTRA_FLIGHT_ID =
            "com.bc004346.travelus.flightId";
    public static final String EXTRA_FLIGHTS =
            "com.bc004346.travelus.flights";
    public static final String EXTRA_FLIGHT =
            "com.bc004346.travelus.flight";
    private static final String KEY_FLIGHT = "Flight";
    protected SwipeRefreshLayout mSwipeRefresh;
    private Flight mFlight;
    private Runnable mLastUpdatedRunnable = new Runnable() {
        @Override
        public void run() {
            if (mFlight == null) return;

            mLastUpdatedHandler.postDelayed(this, MINUTE);
            Date current = new Date();
            int minutesBack = (int) ((current.getTime() - mLastUpdatedDate.getTime() + 10 * SECOND) / MINUTE);
            String message;
            if (minutesBack < 1)
                message = "Just updated";
            else if (minutesBack < 30)
                message = String.format(mActivity.getString(R.string.flightDetailsLabel_UpdatedXMinutesAgo), minutesBack);
            else if (minutesBack < 60)
                message = "Updated over half an hour ago";
            else if (minutesBack < 180)
                message = "Updated over an hour ago";
            else
                message = "Updated ages ago";
            mLastUpdated.setText(message);
        }
    };
    private Activity mActivity;
    private TextSwitcher mCoachFlightCapacity;
    private TextSwitcher mCoachSeatsAvailable;
    private TextSwitcher mCoachNonRevs;
    private TextSwitcher mFirstFlightCapacity;
    private TextSwitcher mFirstSeatsAvailable;
    private TextSwitcher mFirstNonRevs;
    //private TextView mBoardingPriority;
    private TextView mFlightNumber;
    private TextView mFlightStatus;
    private TextView mLastUpdated;
    private TextView mDeparture;
    private TextView mOriginDestination;
    private Button mButtonStandbyList;
    private TextView mSeats;
    private TextView mPNR;
    private View mProgressBar;
    private long mRefreshInterval = MINUTE;
    private Runnable mTimerRunnable = new Runnable() {
        @Override
        public void run() {
            mRefreshInterval = MINUTE * Long.parseLong(SettingsActivity.availabilityRefreshInterval(mActivity));
            log(String.format(mActivity.getString(R.string.flightDetailsLog_RefreshIntervalIsSet), (int) (mRefreshInterval / 60000)));
            mTimerHandler.postDelayed(this, mRefreshInterval);
            if (SettingsActivity.availabilityRefreshEnabled(mActivity))
                updateFlightDetails(mFlight);
        }
    };
    private Date mLastUpdatedDate = new Date();
    private Handler mTimerHandler = new Handler();
    private Handler mLastUpdatedHandler = new Handler();
    private Boolean mAvailabilityRunning = false;
    private Boolean mFlightStatusRunning = false;
    private Boolean mStandbyListRunning = false;

    //</editor-fold>

    //<editor-fold desc="Constructor">
    public static FlightDetailsFragment newInstance(Flight flight) {
        Bundle args = new Bundle();
        args.putSerializable(EXTRA_FLIGHT, flight);
        FlightDetailsFragment fragment = new FlightDetailsFragment();
        fragment.setArguments(args);
        return fragment;
    }
    //</editor-fold>

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            setHasOptionsMenu(true);
            setRetainInstance(true);

            mFlight = (Flight) getArguments().getSerializable(EXTRA_FLIGHT);
            mActivity = getActivity();

            mTimerHandler.postDelayed(mTimerRunnable, mRefreshInterval);
            mLastUpdatedHandler.postDelayed(mLastUpdatedRunnable, MINUTE);
        } catch (Exception e) {
            Utility.log(e.toString());
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                getActivity().finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        mTimerHandler.removeCallbacks(mTimerRunnable);
        mTimerHandler.removeCallbacks(mLastUpdatedRunnable);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        try {
            outState.putSerializable(KEY_FLIGHT, mFlight);
        } catch (Exception e) {
            Utility.log(e.toString());
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_flight, null);

        try {

            if (getActivity().getActionBar() != null)
                getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);

            mSwipeRefresh = (SwipeRefreshLayout) v.findViewById(R.id.fragment_flight_swipeRefresh);
            mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    mSwipeRefresh.setRefreshing(true);
                    updateFlightDetails(mFlight);
                }
            });

            mPNR = (TextView) v.findViewById(R.id.fragment_flight_pnr);
            mSeats = (TextView) v.findViewById(R.id.fragment_flight_seats);
            mFlightStatus = (TextView) v.findViewById(R.id.fragment_flight_status);
            mProgressBar = v.findViewById(R.id.fragment_flight_progressBar_container);
            mLastUpdated = (TextView) v.findViewById(R.id.fragment_flight_last_updated);
            mDeparture = (TextView) v.findViewById(R.id.fragment_flight_departure_date);
            mFlightNumber = (TextView) v.findViewById(R.id.fragment_flight_flight_number);
            mFirstNonRevs = (TextSwitcher) v.findViewById(R.id.fragment_flight_first_standby);
            mCoachNonRevs = (TextSwitcher) v.findViewById(R.id.fragment_flight_coach_standby);
            mFirstSeatsAvailable = (TextSwitcher) v.findViewById(R.id.fragment_flight_first_sa);
            mCoachSeatsAvailable = (TextSwitcher) v.findViewById(R.id.fragment_flight_coach_sa);
            mOriginDestination = (TextView) v.findViewById(R.id.fragment_flight_origin_destination);
            mFirstFlightCapacity = (TextSwitcher) v.findViewById(R.id.fragment_flight_first_capacity);
            mCoachFlightCapacity = (TextSwitcher) v.findViewById(R.id.fragment_flight_coach_capacity);
            mButtonStandbyList = (Button) v.findViewById(R.id.fragment_flight_more);
            if (mFlight.getDeparture().getTime() - new Date().getTime() > Utility.DAY) {
                mButtonStandbyList.setVisibility(View.GONE);
                mSeats.setVisibility(View.GONE);
                v.findViewById(R.id.fragment_flight_standby_message).setVisibility(View.VISIBLE);
            } else {
                mButtonStandbyList.setVisibility(View.VISIBLE);
                mSeats.setVisibility(View.VISIBLE);
                v.findViewById(R.id.fragment_flight_standby_message).setVisibility(View.GONE);
            }
            mButtonStandbyList.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent i = new Intent(mActivity, StandbyActivity.class);
                    i.putExtra(StandbyActivity.EXTRA_OPTIONS, mFlight);
                    startActivity(i);
                }
            });

            ViewSwitcher.ViewFactory viewFactory = new ViewSwitcher.ViewFactory() {
                public View makeView() {
                    TextView myText = new TextView(mActivity);
                    myText.setTextColor(Color.parseColor("#FFFFFF"));
                    myText.setGravity(Gravity.CENTER);
                    return myText;
                }
            };

            mCoachFlightCapacity.setFactory(viewFactory);
            mCoachSeatsAvailable.setFactory(viewFactory);
            mFirstFlightCapacity.setFactory(viewFactory);
            mFirstSeatsAvailable.setFactory(viewFactory);
            mCoachNonRevs.setFactory(viewFactory);
            mFirstNonRevs.setFactory(viewFactory);

            // Declare the in and out animations and initialize them
            Animation out = AnimationUtils.loadAnimation(mActivity, android.R.anim.slide_out_right);
            Animation in = AnimationUtils.loadAnimation(mActivity, android.R.anim.slide_in_left);

            // set the animation type of textSwitcher
            mFirstFlightCapacity.setOutAnimation(out);
            mFirstSeatsAvailable.setOutAnimation(out);
            mCoachFlightCapacity.setOutAnimation(out);
            mCoachSeatsAvailable.setOutAnimation(out);
            mFirstSeatsAvailable.setInAnimation(in);
            mFirstFlightCapacity.setInAnimation(in);
            mCoachFlightCapacity.setInAnimation(in);
            mCoachSeatsAvailable.setInAnimation(in);
            mFirstNonRevs.setOutAnimation(out);
            mCoachNonRevs.setOutAnimation(out);
            mFirstNonRevs.setInAnimation(in);
            mCoachNonRevs.setInAnimation(in);

            if (mFlight != null) setFlight(mFlight);
            updateFlightDetails(mFlight);
        } catch (Exception e) {
            Utility.log(e);
        }
        return v;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.action_item_menu, menu);
    }

    public void updateFlightDetails(Flight flight) {
        mAvailabilityRunning = true;
        mFlightStatusRunning = true;
        mStandbyListRunning = true;
        try {
            if (Utility.getInstance().getTravelUS().getIsLoggedIn() && mFlight != null) {

                mProgressBar.setVisibility(View.VISIBLE);
                mSwipeRefresh.setRefreshing(true);

                getAvailability().execute(flight);
                getFlightStatus().execute(flight);
                if (mButtonStandbyList.getVisibility() == View.VISIBLE)
                    getStandbyList().execute(flight);
                else mStandbyListRunning = false;
            }
        } catch (Exception e) {
            log(e.toString());
            mSwipeRefresh.setRefreshing(false);
            mProgressBar.setVisibility(View.INVISIBLE);
        }
    }

    private AsyncTask<Flight, Void, ArrayList<Passenger>> getStandbyList() {
        return new AsyncTask<Flight, Void, ArrayList<Passenger>>() {

            private Exception exception;

            @Override
            protected ArrayList<Passenger> doInBackground(Flight... flights) {
                ArrayList<Passenger> pax = new ArrayList<Passenger>();
                try {
                    pax = Utility.getInstance().getMobileUSAirways().getStandbyList(flights[0]);
                } catch (Exception e) {
                    exception = e;
                }
                return pax;
            }

            @Override
            protected void onPostExecute(ArrayList<Passenger> passengers) {
                super.onPostExecute(passengers);
                mStandbyListRunning = false;
                tryRemoveSpinner();
                if (exception == null) {
                    setStandbyList(passengers);
                } else if (exception.getClass() == TravelUsException.class) {
                    mLastUpdated.setText(exception.getMessage());
                } else if (exception.getClass() == TravelUsUnavailableException.class) {
                    log(exception);
                    mLastUpdated.setText("Travel US is having problems processing your request. It may be down right now");
                } else {
                    mLastUpdated.setText(exception.getMessage());
                    log(exception, mActivity);
                }
            }
        };
    }

    private AsyncTask<Flight, Void, Flight> getAvailability() {
        return new AsyncTask<Flight, Void, Flight>() {

            private Exception exception;

            @Override
            protected Flight doInBackground(Flight... params) {
                Flight flight = params[0];
                try {
                    flight = Utility.getInstance().getTravelUS().checkAvailability(flight);
                } catch (Exception e) {
                    exception = e;
                }
                return flight;
            }

            @Override
            protected void onPostExecute(Flight flight) {
                mAvailabilityRunning = false;
                tryRemoveSpinner();
                if (exception == null) {
                    setFlightAvailability(flight);
                } else if (exception.getClass() == TravelUsException.class) {
                    mLastUpdated.setText(exception.getMessage());
                } else if (exception.getClass() == TravelUsUnavailableException.class) {
                    log(exception);
                    mLastUpdated.setText("Travel US is having problems processing your request. It may be down right now");
                } else {
                    mLastUpdated.setText(exception.getMessage());
                    log(exception, mActivity);
                }
            }
        };
    }

    private AsyncTask<Flight, Void, Flight> getFlightStatus() {
        return new AsyncTask<Flight, Void, Flight>() {

            private Exception exception;

            @Override
            protected Flight doInBackground(Flight... params) {
                Flight flight = params[0];
                try {
                    flight = Utility.getInstance().getMobileUSAirways().getFlightStatus(flight);
                } catch (Exception e) {
                    exception = e;
                }
                return flight;
            }

            @Override
            protected void onPostExecute(Flight flight) {
                mFlightStatusRunning = false;
                tryRemoveSpinner();
                mLastUpdatedDate = new Date();
                if (exception == null) {
                    setFlightStatus(flight);
                } else if (exception.getClass() == TravelUsException.class) {
                    mLastUpdated.setText(exception.getMessage());
                } else if (exception.getClass() == TravelUsUnavailableException.class) {
                    log(exception);
                    mLastUpdated.setText("Travel US is having problems processing your request. It may be down right now");
                } else {
                    mLastUpdated.setText(exception.getMessage());
                    log(exception, mActivity);
                }
            }
        };
    }

    private void setStandbyList(ArrayList<Passenger> passengers) {

        Set<String> standbyList = SettingsActivity.standbyList(mActivity);
        if (standbyList.size() == 0) {
            mSeats.setText("Select some passengers to see assignment");
            return;
        }
        String seats = "";
        Boolean onThisFlight = false;
        for (Passenger pax : passengers) {
            if (SettingsActivity.isOnStandbyList(mActivity, pax.getName())) onThisFlight = true;
            if (SettingsActivity.isOnStandbyList(mActivity, pax.getName()) && pax.getSeat().length() > 0)
                seats += pax.getSeat() + " ";
        }

        if (seats.length() == 0 && onThisFlight) mSeats.setText("no seats yet");
        else if (seats.length() == 0 && !onThisFlight)
            mSeats.setText("you are not checked in for this flight");
        else mSeats.setText("Seats: " + seats);

    }

    private void tryRemoveSpinner() {
        if (!mFlightStatusRunning && !mAvailabilityRunning && !mStandbyListRunning) {
            mSwipeRefresh.setRefreshing(false);
            mProgressBar.setVisibility(View.INVISIBLE);
            mLastUpdated.setText("Just updated");
        }
    }

    private void setFlight(Flight flight) {
        setFlightAvailability(flight);
        setFlightStatus(flight);
    }

    private void setFlightAvailability(Flight flight) {

        try {
            if (mFlight.getPnr() == null) {
                mPNR.setText("");
                mOriginDestination.setText(String.format("%s %s > %s",
                        mFlight.getOrigin(),
                        MILITARY_TIME.format(mFlight.getDeparture()),
                        mFlight.getDestination()));
            } else {
                mPNR.setText(String.format("PNR: %s", mFlight.getPnr()));
                mOriginDestination.setText(String.format("%s %s > %s %s",
                        mFlight.getOrigin(),
                        MILITARY_TIME.format(mFlight.getDeparture()),
                        mFlight.getDestination(),
                        MILITARY_TIME.format(mFlight.getArrival())));
            }

            mFlightNumber.setText(String.format("Flight: %d", mFlight.getFlightNumber()));
            mDeparture.setText(DAY_DATE.format(mFlight.getDeparture()));

            mFirstFlightCapacity.setText(String.valueOf(flight.getFirstClass().getCapacity()));
            mFirstSeatsAvailable.setText(String.valueOf(flight.getFirstClass().getSeatsAvailable()));
            mFirstNonRevs.setText(String.valueOf(flight.getFirstClass().getNonRevsCount()));

            mCoachFlightCapacity.setText(String.valueOf(flight.getCoach().getCapacity()));
            mCoachSeatsAvailable.setText(String.valueOf(flight.getCoach().getSeatsAvailable()));
            mCoachNonRevs.setText(String.valueOf(flight.getCoach().getNonRevsCount()));
        } catch (Exception e) {
            log(e.getMessage());
        }
    }

    private void setFlightStatus(Flight flight) {
        mFlightStatus.setText(flight.getFlightStatus());
    }
}
